#include "PetersGA.h"

#include <cstring>
using std::memcpy;
using std::memset;

#include <cstdlib>
using std::qsort;

#include <math.h> /* lrint */

#include "../../base.h"
#include "../../math/Random.h"
#include "../../qt/Logger.h"

#include "Individual.h"
#include "ThreadedPopulationEvaluator.h"

namespace GA {

/*
	PetersGA
*/

/*	public	*/

PetersGA::PetersGA(int nPopulation, int nPopulationChildren, Individual* const* population) :
	_nPopulation(nPopulation),
	_nPopulationChildren(nPopulationChildren),
	_bestIndividualCurrent(0),
	_bestIndividualEver(0) {

	/* population */
	_population = new Individual*[nPopulation];
	memcpy(_population, population, nPopulation * sizeof(Individual*));
	_evaluatePopulation();
	_sortPopulation();

	/* population children */
	_populationChildren = new Individual*[nPopulationChildren];
}

PetersGA::~PetersGA() {
	/* best */
	delete _bestIndividualCurrent;
	delete _bestIndividualEver;

	/* individuals */
	deleteall<Individual>(_population, _nPopulation);

	/* populations */
	delete[] _population;
	delete[] _populationChildren;
}

void PetersGA::evolveOneStep() {
	/* at this point, we have a sorted adult population */

	/* generate children */
	int nPopulationChildren         = _nPopulationChildren; /* population size */
	Individual** populationChildren = _populationChildren;  /* population */
	for(int i = 0; i != nPopulationChildren; ++i) {
		populationChildren[i] = _pickParent()->mate(*_pickParent());
	}

	/* age adult population and remove the old ones */
	int nPopulation         = _nPopulation; /* population size */
	Individual** population = _population;  /* population */
	int index = 0;                          /* population new index */
	for(int i = 0; i != nPopulation; ++i) {
		Individual* individual = population[i];

		/* age individual */
		if (individual->incrementAge()) {
			/* still alive */
			population[index] = individual;
			++index;
		} else {
			/* died of old age */
			delete individual;
		}
	}
	/* zero the rest of the population space */
	memset(population + index, 0, (nPopulation - index) * sizeof(Individual*));

	/* address of the first child in the population */
	Individual** firstChild = population + (nPopulation - nPopulationChildren);

	/* remove the less fit adults that won't make it */
	Individual** individual    = firstChild;
	Individual** populationEnd = population + nPopulation;
	while(individual != populationEnd && *individual != 0) {
		delete *individual;
		++individual;
	}

	/* move the children population to adults */
	memcpy(firstChild, populationChildren, nPopulationChildren * sizeof(Individual*));

	/* evaluate the new adult population */
	_evaluatePopulation();

	/* sort the new adult population */
	_sortPopulation();

	/* update best individuals */
	_updateBestIndividuals();
}

const Individual& PetersGA::getBestIndividualCurrent() const {
	return *_bestIndividualCurrent;
}

const Individual& PetersGA::getBestIndividualEver() const {
	return *_bestIndividualEver;
}


/*	private	*/

Individual* PetersGA::_pickParent() const {
	/* random */
	Random& random = Random::getInstance();

	/* resulting individual */
	Individual* individual;

	if (random.getBool(PETERS_GA_RANDOM_PARENT_COEFFICIENT)) {
		/* pick a parent completely at random */
		do {
			individual = _population[random.getInt(_nPopulation)];
		} while(individual == 0);
	} else {
		/* pick a parent amongst the best individuals */
		int potentialParents = lrint(PETERS_GA_PARENTS_COEFFICIENT * (double)_nPopulation);

		do {
			individual = _population[random.getInt(potentialParents)];
		} while(individual == 0);
	}

	return individual;
}

void PetersGA::_evaluatePopulation() {
	ThreadedPopulationEvaluator evaluator(_nPopulation, _population);
	evaluator.evaluate();
}

int qsortIndividualHelper(void const* individual1, void const* individual2) {
	Individual const* i1 = *(static_cast<Individual const* const*>(individual1));
	Individual const* i2 = *(static_cast<Individual const* const*>(individual2));

	if (i1 == 0 && i2 == 0) {
		return 0;
	} else if (i1 == 0) {
		return 1;
	} else if (i2 == 0) {
		return -1;
	}

//	Individual const& i1 = *(static_cast<Individual const*>(individual1)); 
//	Individual const& i2 = *(static_cast<Individual const*>(individual2)); 

	if (*i2 > *i1) {
		return 1;
	} else if (*i1 > *i2) {
		return -1;
	} else {
		return 0;
	}
}

void PetersGA::_sortPopulation() {
	qsort(_population, _nPopulation, sizeof(Individual*), &qsortIndividualHelper);
}

void PetersGA::_updateBestIndividuals() {
	/* best for this generation */
	Individual* currentTop = *_population;

	/* update best current*/
	delete _bestIndividualCurrent;
	_bestIndividualCurrent = currentTop->copy();

	/* update the best ever */
	if (_bestIndividualEver == 0 || ((*currentTop) > (*_bestIndividualEver))) {
		delete _bestIndividualEver;
		_bestIndividualEver = currentTop->copy();
	}
}

} //GA

